<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */
namespace App\Service;

use App\Utils\Redis;
use Hyperf\Di\Annotation\Inject;
use Swoole\WebSocket\Server;

class WebSocketService
{
//    /**
//     * @Inject
//     * @var Server
//     */
//    protected $server;

    private $redisFdPrefix = 'mm_diary_';

    /**
     * 处理各种socket事件.
     * @param $fd
     * @param $event
     */
    public function socketEvent(int $fd, string $event, array $data = []): void
    {
        switch ($event) {
            case 'open':
                $pushData = [
                    'client_id' => $fd,
                    'type' => 'init',
                ];
                $this->pushMsg($fd, $pushData);
                break;
            case 'received':
                break;
            case 'bind':
                $channel = (string) $data['channel'];
                $this->bindRelation($fd, $channel);
                break;
            case 'close':
                $this->removeRelation($fd);
                break;
        }
    }

    /**
     * 通过fd推送消息.
     */
    public function pushByFd(int $fd, array $data = []): void
    {
        $this->pushMsg($fd, $data);
    }

    /**
     * 通过channel推送消息.
     */
    public function pushByChannel(string $channel, array $data = []): void
    {
        $redis = Redis::getInstance();
        $fds = $redis->sMembers($channel);
        $data = array_merge($data, ['type' => 'push']);
        $this->pushMsg($fds, $data);
    }

    /**
     * 推送消息.
     * @param $fds
     * @param $data
     */
    private function pushMsg($fds, array $data = []): void
    {
        //$redis = Redis::getInstance();
        $server = server();
        $data = json_encode($data);
        if (! is_array($fds)) {
            $server->push((int) $fds, $data);
//            if ($redis->get($this->redisFdPrefix . $fds)) {
//                $server->push((int) $fds, $data);
//            } else {
//                $this->removeRelation((int) $fds);
//            }
        } else {
            foreach ($fds as $fd) {
//                if ($redis->get($this->redisFdPrefix . $fd)) {
//                    $server->push((int) $fd, $data);
//                } else {
//                    $this->removeRelation((int) $fd);
//                }
                $server->push((int) $fd, $data);
            }
        }
    }

    /**
     * 绑定关系.
     * @param $fd
     * @param $channel
     */
    private function bindRelation(int $fd, string $channel): void
    {
        $redis = Redis::getInstance();
        $redis->sAdd($channel, $fd);
        $key = $this->redisFdPrefix . $fd;
        $redis->set($key, $channel);
    }

    /**
     * 移除绑定关系.
     * @param $fd
     */
    private function removeRelation($fd): void
    {
        $redis = Redis::getInstance();
        $key = $this->redisFdPrefix . $fd;
        $channel = $redis->get($key);
        $redis->del($key);
        if (! empty($channel)) {
            $redis->sRem($channel, $fd);
        }
    }
}
